package com.ruoyi.yuyuan.Service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.yuyuan.DTO.BlogPracticeDTO;
import com.ruoyi.yuyuan.DTO.Result;
import com.ruoyi.yuyuan.Entity.BlogAgreement;
import com.ruoyi.yuyuan.Entity.BlogPractice;
import com.ruoyi.yuyuan.Entity.Event;
import com.ruoyi.yuyuan.Event.EventProducer;
import com.ruoyi.yuyuan.Mapper.AgreementBlogMapper;
import com.ruoyi.yuyuan.Mapper.PracticeBlogMapper;
import com.ruoyi.yuyuan.Service.IElasticSearch;
import com.ruoyi.yuyuan.Service.IPracticeBlogService;
import com.ruoyi.yuyuan.Utils.IdGenerator;
import com.ruoyi.yuyuan.Utils.MyUtils;
import com.ruoyi.yuyuan.Utils.SensitiveFilter;
import com.ruoyi.yuyuan.Utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.yuyuan.Utils.CommunityConstant.*;
import static com.ruoyi.yuyuan.Utils.RedisConstants.BLOG_PUBLISH_LOCK;
import static com.ruoyi.yuyuan.Utils.RedisConstants.BLOG_UPDATE_LOCK;

/**
 * @Author: kestrel
 * @Version:1.0
 * @Date: 2024/5/29
 */
@Slf4j
@Service
public class PracticeBlogServiceImpl extends ServiceImpl<PracticeBlogMapper, BlogPractice> implements IPracticeBlogService {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private PracticeBlogMapper practiceBlogMapper;

    @Autowired
    private EventProducer eventProducer;

    @Autowired
    private IElasticSearch elasticSearch;

    @Autowired
    private MyUtils myUtils;

    @Autowired
    private SensitiveFilter sensitiveFilter;
    @Override
    public Result publishPractice(BlogPracticeDTO blogPracticeDTO) throws InterruptedException {
        Long userId = UserHolder.getUser().getId();
        //加入分布式锁(解决单个用户发帖时发生线程安全问题)
        RLock lock = redissonClient.getLock(BLOG_PUBLISH_LOCK + userId);
        //尝试获取锁，无等待时间，无限释放时间(含看门狗机制)
        boolean isSuccess = lock.tryLock(1, TimeUnit.SECONDS);
        //获取锁失败
        if (!isSuccess) {
            return Result.fail("发帖太频繁了哦~请稍后再试!");
        }
        BlogPractice blogPractice = BeanUtil.copyProperties(blogPracticeDTO, BlogPractice.class);
        blogPractice.setId(idGenerator.nextBlogId((short) 0));
        blogPractice.setUserId(userId);
        blogPractice.setUserName(UserHolder.getUser().getNickName());
        blogPractice.setIcon(UserHolder.getUser().getIcon());
        LocalDateTime now = LocalDateTime.now();
        blogPractice.setCreateTime(now);
        blogPractice.setUpdateTime(now);
        // 过滤敏感词
        blogPractice.setDemand(sensitiveFilter.filter(blogPractice.getDemand()));
        blogPractice.setLocation(sensitiveFilter.filter(blogPractice.getLocation()));
        blogPractice.setContent(sensitiveFilter.filter(blogPractice.getContent()));

        practiceBlogMapper.insert(blogPractice);

        // 触发发帖事件，存到ES服务器
        Event event = new Event(
                TOPIC_PUBLIC,
                UserHolder.getUser().getId(),
                ENTITY_TYPE_POST,
                blogPractice.getId(),
                blogPractice,
                "BlogPractice");
        eventProducer.fireEvent(event);

        lock.unlock();
        return Result.ok(blogPractice);
    }

    @Override
    public Result updatePractice(BlogPracticeDTO blogPracticeDTO, Long blogId) throws InterruptedException {
        Long userId = UserHolder.getUser().getId();
        //加入分布式锁(解决单个用户发帖时发生线程安全问题)
        RLock lock = redissonClient.getLock(BLOG_UPDATE_LOCK + userId);
        //尝试获取锁，无等待时间，无限释放时间(含看门狗机制)
        boolean isSuccess = lock.tryLock(1, TimeUnit.SECONDS);
        //获取锁失败
        if (!isSuccess) {
            return Result.fail("更帖太频繁了哦~请稍后再试!");
        }
        BlogPractice blogPractice = BeanUtil.copyProperties(blogPracticeDTO, BlogPractice.class);
        blogPractice.setId(blogId);
        LocalDateTime now = LocalDateTime.now();
        blogPractice.setUpdateTime(now);
        practiceBlogMapper.updateById(blogPractice);

        // 触发删帖事件，删除ES服务器内容
        Event event = new Event(
                TOPIC_UPDATE,
                UserHolder.getUser().getId(),
                ENTITY_TYPE_POST,
                blogPractice.getId(),
                blogPractice,
                "BlogAgreement");
        eventProducer.fireEvent(event);

        lock.unlock();
        return Result.ok(blogPractice);
    }

    @Override
    public Result getSinglePractice(Long blogId) {
        return Result.ok(practiceBlogMapper.selectById(blogId));
    }

    @Override
    public Result getPractices(Long startId) {
        //分页查询传入0时默认读取最新(最迟创建)数据，进行处理
        startId = myUtils.zeroHandler(startId, 0L,"BlogPractice");
        List<BlogPractice> list = practiceBlogMapper.getPractices(startId);
        for (BlogPractice blogPractice : list) {
            //处理贴子图片临时链接
            blogPractice.handlerImgs();
        }
        //返回结果，以及长度
        return Result.ok(list,((Integer)list.size()).longValue());
    }

    @Override
    public Result getSearchPractices(String searchKeyWord, Short type) throws IOException {
        return elasticSearch.searchPracticeBlog(searchKeyWord);
    }
}
